package cn.ratel.db;

import cn.ratel.kit.CollectionKit;
import com.google.common.base.Joiner;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Sqls {
	private String tableName;
	private StringBuilder baseSql;
	private StringBuilder appendSql = new StringBuilder();
	private List<Object> params = new ArrayList<Object>();
	private static final String BASE_SQL_TPL = "select %s from %s where true ";

	Sqls(String tableName) {
		this.tableName = tableName;
		baseSql = new StringBuilder(String.format(BASE_SQL_TPL, "*", tableName));
	}

	Sqls(String selectedFields, String tableName) {
		this.tableName = tableName;
		baseSql = new StringBuilder(String.format(BASE_SQL_TPL, selectedFields, tableName));
	}

	public String sql() {
		return baseSql.append(appendSql).toString().replaceAll("\\s+", " ");
	}

	public String countSql() {
		String sql = (String.format(BASE_SQL_TPL, "count(1)", tableName) + appendSql).replaceAll("\\s+", " ");
		int orderByIndex = StringUtils.lastIndexOf(sql, " order by ");
		if (orderByIndex > -1) {
			sql = StringUtils.substring(sql, 0, orderByIndex);
		}
		int limitIndex = StringUtils.lastIndexOfIgnoreCase(sql, " limit ");
		if (limitIndex > -1) {
			sql = StringUtils.substring(sql, 0, limitIndex);
		}
		return sql;
	}

	public Sqls and(String sqlPart, Object... params) {
		return and(true, sqlPart, params);
	}

	public Sqls and(boolean expression, String sqlPart, Object... params) {
		return appendSql(expression, " and " + sqlPart, params);
	}

	public Sqls or(String sqlPart, Object... params) {
		return or(true, sqlPart, params);
	}

	public Sqls or(boolean expression, String sqlPart, Object... params) {
		return appendSql(expression, " or " + sqlPart, params);
	}

	public Sqls limit(int start, int pageSize) {
		return appendSql(true, String.format(" limit %d, %d", start, pageSize));
	}

	public Sqls append(String sqlPart, Object... params) {
		return append(true, sqlPart, params);
	}

	public Sqls append(boolean expression, String sqlPart, Object... params) {
		return appendSql(expression, " " + sqlPart, params);
	}

	public Sqls in(boolean expression, String inColumn, List<Integer> ids) {
		if (CollectionKit.isEmpty(ids)) {
			return this;
		}
		if (expression) {
			return appendSql(true, inColumn + " in(" + Joiner.on(",").join(ids) + ")");
		}
		return this;
	}

	public Sqls orderBy(String sqlPart) {
		return append(true, " order by " + sqlPart);
	}

	public Object[] params() {
		return this.params.toArray();
	}

	private Sqls appendSql(boolean expression, String sqlPart, Object... params) {
		if (expression) {
			appendSql.append(" ").append(sqlPart);
			if (params != null) {
				this.params.addAll(Arrays.asList(params));
			}
		}
		return this;
	}

}